module.exports = class JsonKit {
  _findFirst(json, key, value, includeTree = false) {
    if (Array.isArray(json)) {
      return this._findFirstArray(json, key, value, includeTree);
    } else if (typeof json === "object" && json !== null) {
      return this._findFirstObject(json, key, value, includeTree);
    } else {
      return this._findFirstObject(
        JSON.parse(JSON.stringify(json)),
        key,
        value,
        includeTree
      );
    }
  }

  _findFirstArray(array, key, value, includeTree) {
    if (this._checkContains(array, key, value)) {
      for (let item of array) {
        if (typeof item === "object" && item !== null) {
          let target = this._findFirstObject(item, key, value, includeTree);
          if (target !== null) {
            return target;
          }
        }
      }
    }
    return null;
  }

  _findFirstObject(item, key, value, includeTree) {
    if (this._checkContains(item, key, value)) {
      let baseValue = item[key];
      if (baseValue !== undefined && baseValue == value) {
        return item;
      } else {
        for (let k in item) {
          let nValue = item[k];
          if (Array.isArray(nValue)) {
            let target = this._findFirstArray(nValue, key, value, includeTree);
            if (target !== null) {
              if (includeTree) {
                item[k] = [target];
                return item;
              } else {
                return target;
              }
            }
          } else if (typeof nValue === "object" && nValue !== null) {
            let target = this._findFirstObject(nValue, key, value, includeTree);
            if (target !== null) {
              if (includeTree) {
                item[k] = target;
                return item;
              } else {
                return target;
              }
            }
          }
        }
      }
    }
    return null;
  }

  static findFirstTree(item, ...keyAndValue) {
    return new JsonKit()._find(item, ...keyAndValue);
  }

  _find(item, ...keyAndValue) {
    if (keyAndValue.length % 2 !== 0) {
      throw new Error("keyAndValue必须成对出现");
    }

    let target = item;
    if (Array.isArray(item)) {
      for (let obj of item) {
        if (typeof obj === "object" && obj !== null) {
          let result = this._find(obj, ...keyAndValue);
          if (result !== null) {
            return result;
          }
        }
      }
      return null;
    } else {
      for (let i = 0; i < keyAndValue.length; i += 2) {
        let key = keyAndValue[i];
        let value = keyAndValue[i + 1];
        target = this._findFirst(target, key, value, true);
        if (target === null) {
          return null;
        } else if (i + 2 === keyAndValue.length) {
          return target;
        }
      }
      return null;
    }
  }

  _checkContains(json, key, value) {
    return JSON.stringify(json).includes(value);
  }

  static remove(item, props) {
    // 递归删除指定属性，item为对象或数组
    if (typeof item === "object" && item !== null) {
      if (Array.isArray(item)) {
        return item.map((element) => JsonKit.remove(element, props));
      } else {
        props.forEach((prop) => {
          delete item[prop];
        });
        // 二层处理
        Object.keys(item).forEach((key) => {
          item[key] = JsonKit.remove(item[key], props);
        });

        return item;
      }
    } else {
      return item;
    }
  }
};
